package com.lxk.cms.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lxk.cms.constants.CmsReplyConfigConstants;
import com.lxk.cms.domain.CmsReply;
import com.lxk.cms.domain.bo.CmsReplyBo;
import com.lxk.cms.domain.bo.CmsReplyCreateBo;
import com.lxk.cms.domain.vo.AppCmsReplyRespVo;
import com.lxk.cms.domain.vo.CmsReplyVo;
import com.lxk.cms.enums.CmsReplyTypeEnum;
import com.lxk.cms.mapper.CmsReplyMapper;
import com.lxk.cms.service.ICmsReplyService;
import com.lxk.ums.domain.vo.UmsUserVo;
import com.lxk.ums.service.IUmsUserService;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.enums.CommonAuditStatusEnum;
import org.dromara.common.core.enums.SysConfigSwitchEnum;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.util.PageUtils;
import org.dromara.system.service.ISysConfigService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 通用评论Service业务层处理
 *
 * @author soda
 * @date 2024-08-06
 */
@RequiredArgsConstructor
@Service
public class CmsReplyServiceImpl implements ICmsReplyService {

    private final CmsReplyMapper baseMapper;
    private final ISysConfigService sysConfigService;
    private final IUmsUserService userService;

    /**
     * 查询IdList通用评论Map
     */
    @Override
    public Map<Long, CmsReplyVo> queryMapByIdList(List<Long> idList) {
        return this.queryByIdList(idList).stream().collect(Collectors.toMap(CmsReplyVo::getId, v -> v));
    }

    /**
     * 查询通用评论Map
     */
    @Override
    public Map<Long, CmsReplyVo> queryMap(CmsReplyBo bo) {
        return this.queryList(bo).stream().collect(Collectors.toMap(CmsReplyVo::getId, v -> v));
    }

    /**
     * 查询通用评论IdList
     */
    @Override
    public List<CmsReplyVo> queryByIdList(List<Long> idList) {
        if (CollUtil.isEmpty(idList)) {
            return CollUtil.newArrayList();
        }
        LambdaQueryWrapper<CmsReply> lqw = Wrappers.lambdaQuery();
        lqw.in(CmsReply::getId, idList);
        return baseMapper.selectVoList(lqw);
    }

    /**
     * 查询通用评论
     *
     * @param id 主键
     * @return 通用评论
     */
    @Override
    public CmsReplyVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 分页查询通用评论列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 通用评论分页列表
     */
    @Override
    public TableDataInfo<CmsReplyVo> queryPageList(CmsReplyBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<CmsReply> lqw = buildQueryWrapper(bo);
        Page<CmsReplyVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的通用评论列表
     *
     * @param bo 查询条件
     * @return 通用评论列表
     */
    @Override
    public List<CmsReplyVo> queryList(CmsReplyBo bo) {
        LambdaQueryWrapper<CmsReply> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<CmsReply> buildQueryWrapper(CmsReplyBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<CmsReply> lqw = Wrappers.lambdaQuery();
        lqw.orderByDesc(CmsReply::getId);
        lqw.eq(bo.getUid() != null, CmsReply::getUid, bo.getUid());
        lqw.eq(bo.getType() != null, CmsReply::getType, bo.getType());
        lqw.eq(StringUtils.isNotBlank(bo.getContent()), CmsReply::getContent, bo.getContent());
        lqw.eq(StringUtils.isNotBlank(bo.getImageUrl()), CmsReply::getImageUrl, bo.getImageUrl());
        lqw.eq(StringUtils.isNotBlank(bo.getVideoUrl()), CmsReply::getVideoUrl, bo.getVideoUrl());
        lqw.eq(bo.getParentId() != null, CmsReply::getParentId, bo.getParentId());
        lqw.eq(bo.getParentUid() != null, CmsReply::getParentUid, bo.getParentUid());
        lqw.eq(bo.getReviewId() != null, CmsReply::getReviewId, bo.getReviewId());
        lqw.eq(bo.getReviewUid() != null, CmsReply::getReviewUid, bo.getReviewUid());
        lqw.eq(bo.getLikeCount() != null, CmsReply::getLikeCount, bo.getLikeCount());
        lqw.eq(bo.getLikeVirtually() != null, CmsReply::getLikeVirtually, bo.getLikeVirtually());
        lqw.eq(bo.getCountReply() != null, CmsReply::getCountReply, bo.getCountReply());
        lqw.eq(bo.getAuditStatus() != null, CmsReply::getAuditStatus, bo.getAuditStatus());
        lqw.eq(StringUtils.isNotBlank(bo.getRefusal()), CmsReply::getRefusal, bo.getRefusal());
        lqw.eq(bo.getKeyId() != null, CmsReply::getKeyId, bo.getKeyId());
        lqw.eq(StringUtils.isNotBlank(bo.getCategory()), CmsReply::getCategory, bo.getCategory());
        lqw.eq(bo.getToUid() != null, CmsReply::getToUid, bo.getToUid());
        lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
            CmsReply::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
        lqw.between(params.get("beginUpdateTime") != null && params.get("endUpdateTime") != null,
            CmsReply::getUpdateTime, params.get("beginUpdateTime"), params.get("endUpdateTime"));
        return lqw;
    }

    /**
     * 新增通用评论
     *
     * @param bo 通用评论
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(CmsReplyBo bo) {
        CmsReply add = MapstructUtils.convert(bo, CmsReply.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改通用评论
     *
     * @param bo 通用评论
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(CmsReplyBo bo) {
        CmsReply update = MapstructUtils.convert(bo, CmsReply.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(CmsReply entity) {
    }

    /**
     * 校验并批量删除通用评论信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    @Transactional
    public CmsReplyVo addReply(CmsReplyCreateBo cmsReplyCreateBo) {
        CmsReplyBo cmsReplyBo = MapstructUtils.convert(cmsReplyCreateBo, CmsReplyBo.class);
        if (cmsReplyBo == null) {
            throw new ServiceException("参数错误");
        }
        cmsReplyBo.setType(CmsReplyTypeEnum.COMMENT.getCode());
        cmsReplyBo.setUid(cmsReplyCreateBo.getUserId());
        cmsReplyBo.setAuditStatus(CommonAuditStatusEnum.PASS.getStatus());
        cmsReplyBo.setParentId(0L);
        if (cmsReplyCreateBo.getReplyId() > 0) {
            //说明是回复消息
            cmsReplyBo.setType(CmsReplyTypeEnum.REPLY.getCode());
            CmsReplyVo tempReply = baseMapper.selectVoById(cmsReplyCreateBo.getReplyId());
            if (tempReply.getType().equals(CmsReplyTypeEnum.COMMENT.getCode())) {
                cmsReplyBo.setParentId(tempReply.getId());
                cmsReplyBo.setParentUid(tempReply.getUid());
                cmsReplyBo.setToUid(tempReply.getUid());
            } else {
                cmsReplyBo.setParentId(tempReply.getParentId());
                cmsReplyBo.setParentUid(tempReply.getParentUid());
                cmsReplyBo.setReviewId(tempReply.getId());
                cmsReplyBo.setReviewUid(tempReply.getUid());
                cmsReplyBo.setToUid(tempReply.getUid());
            }
        } else {
            cmsReplyBo.setToUid(cmsReplyCreateBo.getAuthorUserId());
        }
        //评论审核开关，这里使用了
        String replyAuditSwitch = sysConfigService.selectConfigByKey(CmsReplyConfigConstants.replyAuditSwitchPrefix + cmsReplyBo.getCategory());
        if (SysConfigSwitchEnum.isEnable(replyAuditSwitch)) {
            cmsReplyBo.setAuditStatus(CommonAuditStatusEnum.WAITING.getStatus());
        }
        //为了事务继承使用Spring获取类
        boolean save = SpringUtils.getBean(getClass()).insertByBo(cmsReplyBo);
        if (!save) {
            throw new ServiceException("笔记评论失败");
        }
        CmsReplyVo cmsReplyVo = baseMapper.selectVoById(cmsReplyBo.getId());
        if (cmsReplyVo == null) {
            UmsUserVo umsUserVo = userService.queryById(cmsReplyVo.getUid());
            if (umsUserVo != null) {
                cmsReplyVo.setNickName(umsUserVo.getNickName());
                cmsReplyVo.setAvatar(umsUserVo.getAvatar());
            }
        }
        return cmsReplyVo;
    }

    @Override
    public Page<CmsReplyVo> queryPageByKeyId(Long keyId, String category, PageQuery pageQuery) {
        LambdaQueryWrapper<CmsReply> lqw = Wrappers.lambdaQuery();
        lqw.eq(CmsReply::getKeyId, keyId);
        lqw.eq(CmsReply::getCategory, category);
        lqw.eq(CmsReply::getType, CmsReplyTypeEnum.COMMENT.getCode());
        lqw.eq(CmsReply::getAuditStatus, CommonAuditStatusEnum.PASS.getStatus());
        lqw.orderByDesc(CmsReply::getId);
        return baseMapper.selectVoPage(pageQuery.build(), lqw);
    }

    @Override
    public List<CmsReplyVo> findReplyByParentId(Long id) {
        LambdaQueryWrapper<CmsReply> lqw = Wrappers.lambdaQuery();
        lqw.eq(CmsReply::getParentId, id);
        lqw.eq(CmsReply::getType, CmsReplyTypeEnum.COMMENT.getCode());
        lqw.eq(CmsReply::getAuditStatus, CommonAuditStatusEnum.PASS.getStatus());
        lqw.orderByDesc(CmsReply::getId);
        return baseMapper.selectVoList(lqw);
    }

    @Override
    public Page<AppCmsReplyRespVo> findNotePagePage(Long id, String category, PageQuery pageQuery) {
        Page<CmsReplyVo> communityReplyPage = this.queryPageByKeyId(id, category, pageQuery);
        List<CmsReplyVo> list = communityReplyPage.getRecords();
        if (CollUtil.isEmpty(list)) {
            return pageQuery.build();
        }
        List<AppCmsReplyRespVo> responseList = list.stream().map(r -> {
            AppCmsReplyRespVo replyResponse = MapstructUtils.convert(r, AppCmsReplyRespVo.class);
            if (replyResponse != null) {
                replyResponse.setAuditStatus(null);
                //TODO 循环查询待优化，可以批量查在java中进行groupBy
                List<CmsReplyVo> replyList = this.findReplyByParentId(r.getId());
                if (CollUtil.isNotEmpty(replyList)) {
                    List<AppCmsReplyRespVo> childReplyList = MapstructUtils.convert(replyList, AppCmsReplyRespVo.class);
                    replyResponse.setReplyList(childReplyList);
                }
            }
            return replyResponse;
        }).collect(Collectors.toList());
        responseSetUserName(responseList);
        return PageUtils.copyPageInfo(communityReplyPage, responseList);
    }

    private void responseSetUserName(List<AppCmsReplyRespVo> responseList) {
        List<Long> uidList = new ArrayList<>();
        responseList.forEach(r -> {
            if (!uidList.contains(r.getUid())) {
                uidList.add(r.getUid());
            }
            if (CollUtil.isNotEmpty(r.getReplyList())) {
                r.getReplyList().forEach(rc -> {
                    if (!uidList.contains(rc.getUid())) {
                        uidList.add(rc.getUid());
                    }
                    if (rc.getReviewUid() > 0 && !uidList.contains(rc.getReviewUid())) {
                        uidList.add(rc.getReviewUid());
                    }
                });
            }
        });
        List<UmsUserVo> umsUserVos = userService.queryByIdList(uidList);
        Map<Long, UmsUserVo> userMap = umsUserVos.stream().collect(Collectors.toMap(UmsUserVo::getId, umsUserVo -> umsUserVo));
        responseList.forEach(r -> {
            r.setNickname(userMap.get(r.getUid()).getNickName());
            r.setAvatar(userMap.get(r.getUid()).getAvatar());
            if (CollUtil.isNotEmpty(r.getReplyList())) {
                r.getReplyList().forEach(rc -> {
                    rc.setNickname(userMap.get(rc.getUid()).getNickName());
                    rc.setAvatar(userMap.get(rc.getUid()).getAvatar());
                    if (rc.getReviewUid() > 0) {
                        rc.setReviewUserNickname(userMap.get(rc.getReviewUid()).getNickName());
                    }
                });
            }
        });
    }
}
